﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Interactivity;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using Microsoft.Practices.Prism.Interactivity;

namespace ConfApp.Infrastructure.Behaviours
{
    /// <summary>
    /// Associates a command to an <see cref="MediaElement"/>.
    /// </summary>
    [CLSCompliant(false)]
    public class MediaEndedCommand : Behavior<MediaElement>
    {
        ///<summary>
        /// The parameter to use when calling methods on the <see cref="ICommand"/> interface.
        ///</summary>
        public static readonly DependencyProperty CommandParameterBindingProperty =
            DependencyProperty.Register("CommandParameterBinding", typeof(Binding), typeof(MediaEndedCommand), new PropertyMetadata(HandleBindingChanged));

        /// <summary>
        /// The binding for <see cref="ICommand"/> to invoke based on the MediaElement's events.
        /// </summary>
        public static readonly DependencyProperty CommandBindingProperty =
            DependencyProperty.Register("CommandBinding", typeof(Binding), typeof(MediaEndedCommand), new PropertyMetadata(HandleBindingChanged));

        private MediaEndedCommandBinding binding;

        /// <summary>
        /// The <see cref="Binding"/> to use that results in an <see cref="ICommand"/>.
        /// </summary>
        public Binding CommandBinding
        {
            get { return (Binding)GetValue(CommandBindingProperty); }
            set { SetValue(CommandBindingProperty, value); }
        }

        /// <summary>
        /// The <see cref="Binding"/> for the command parameter to use with the <see cref="CommandBinding"/>.
        /// </summary>
        public Binding CommandParameterBinding
        {
            get { return (Binding)GetValue(CommandParameterBindingProperty); }
            set { SetValue(CommandParameterBindingProperty, value); }
        }

        /// <summary>
        /// The <see cref="ICommand"/> to bind to the <see cref="MediaElement"/>.
        /// </summary>
        protected ICommand Command { get; set; }

        /// <summary>
        /// The value to use when calling <see cref="Command"/> methods.
        /// </summary>
        protected object CommandParameter { get; set; }

        /// <summary>
        /// Called after the behavior is attached to an AssociatedObject.
        /// </summary>
        /// <remarks>
        /// Override this to hook up functionality to the AssociatedObject.
        /// </remarks>
        protected override void OnAttached()
        {
            base.OnAttached();
            this.CreateBinding();
        }


        /// <summary>
        /// Invoked when the <see cref="Binding"/> changes.
        /// </summary>
        /// <param name="e"></param>
        protected void OnBindingChanged(DependencyPropertyChangedEventArgs e)
        {
            this.CreateBinding();
        }

        private static void HandleBindingChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ((MediaEndedCommand)sender).OnBindingChanged(e);
        }

        private void CreateBinding()
        {
            if (this.CommandBinding == null || this.AssociatedObject == null) return;
            if (this.binding != null)
            {
                this.binding.Detach();
            }

            this.binding = new MediaEndedCommandBinding(
                this.AssociatedObject,
                (ICommand) this.CommandBinding,
                () => this.CommandParameter);
        }

        /// <summary>
        /// Binds an <see cref="MediaEndedCommand"/> to a <see cref="ICommand"/>.
        /// </summary>
        private class MediaEndedCommandBinding
        {
            private readonly ICommand command;
            private readonly MediaElement mediaElement;
            private readonly Func<object> parameterGetter;

            /// <summary>
            /// 
            /// </summary>
            /// <param name="mediaElement"></param>
            /// <param name="command"></param>
            /// <param name="parameterGetter"></param>
            public MediaEndedCommandBinding(MediaElement mediaElement, ICommand command, Func<object> parameterGetter)
            {
                this.command = command;
                this.mediaElement = mediaElement;
                this.parameterGetter = parameterGetter;
                //this.mediaElement.IsEnabled = this.command.CanExecute(parameterGetter());

                //this.command.CanExecuteChanged += this.CommandCanExecuteChanged;
                this.mediaElement.MediaEnded += this.MediaEnded;
                
            }

            public void Detach()
            {
                this.mediaElement.MediaEnded -= this.MediaEnded;
                //this.command.CanExecuteChanged -= this.CommandCanExecuteChanged;
            }

            private void MediaEnded(object s, EventArgs e)
            {
                this.command.Execute(this.parameterGetter());
                //mediaElement.SelectedItem = null;
            }

            //private void CommandCanExecuteChanged(object s, EventArgs ea)
            //{
            //    //this.mediaElement.IsEnabled = this.command.CanExecute(this.parameterGetter());
            //}
        }
    }
}
